﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Revit;

namespace Assist
{
	public class CurveAssistFunc
	{
		public static CurveType GetCurveType(Curve c)
		{
			if (c as Line != null)
			{
				return CurveType.eLine;
			}
			if (c as Arc != null)
			{
				return CurveType.eArc;
			}
			return CurveType.eError;
		}

		public static Line Combine2Line(UIApplication uiApp, Line l1, Line l2)
		{
			XYZ vector = LineAssistFunc.GetVector(l1);
			XYZ vector2 = LineAssistFunc.GetVector(l2);
			if (GeoUtil.IsParallel(vector, vector2))
			{
				XYZ hyendPoint = l1.GetEndPoint(0);
				XYZ hyendPoint2 = l1.GetEndPoint(1);
				XYZ hyendPoint3 = l2.GetEndPoint(0);
				XYZ hyendPoint4 = l2.GetEndPoint(1);
				if (CurveAssistFunc.GetClosestPointTo(uiApp, l1, hyendPoint3, true).DistanceTo(hyendPoint3) < CurveAssistFunc.precision)
				{
					List<XYZ> list = new List<XYZ>();
					list.Add(hyendPoint);
					list.Add(hyendPoint2);
					list.Add(hyendPoint3);
					list.Add(hyendPoint4);
					GeoUtil.SortPointByDirect(uiApp, list, vector);
					return uiApp.Application.CreatYJKLine(list.First<XYZ>(), list.Last<XYZ>(), true);
				}
			}
			return null;
		}

		public static Curve Combine2Curve(UIApplication uiApp, Curve c1, Curve c2)
		{
			Line line = c1 as Line;
			if (line != null)
			{
				Line line2 = c2 as Line;
				if (line2 != null)
				{
					XYZ vector = LineAssistFunc.GetVector(line);
					XYZ vector2 = LineAssistFunc.GetVector(line2);
					if (GeoUtil.IsParallel(vector, vector2))
					{
						XYZ hyendPoint = line.GetEndPoint(0);
						XYZ hyendPoint2 = line.GetEndPoint(1);
						XYZ hyendPoint3 = line2.GetEndPoint(0);
						XYZ hyendPoint4 = line2.GetEndPoint(1);
						if (hyendPoint.DistanceTo(hyendPoint3) < CurveAssistFunc.precision || hyendPoint.DistanceTo(hyendPoint4) < CurveAssistFunc.precision || hyendPoint2.DistanceTo(hyendPoint3) < CurveAssistFunc.precision || hyendPoint2.DistanceTo(hyendPoint4) < CurveAssistFunc.precision)
						{
							List<XYZ> list = new List<XYZ>();
							list.Add(hyendPoint);
							list.Add(hyendPoint2);
							list.Add(hyendPoint3);
							list.Add(hyendPoint4);
							GeoUtil.SortPointByDirect(uiApp, list, vector);
							return uiApp.Application.CreatYJKLine(list.First<XYZ>(), list.Last<XYZ>(), true);
						}
					}
				}
			}
			Arc arc = c1 as Arc;
			if (arc != null)
			{
				Arc arc2 = c2 as Arc;
				if (arc2 != null)
				{
					double radius = arc.Radius;
					double radius2 = arc2.Radius;
					XYZ center = arc.Center;
					XYZ center2 = arc2.Center;
					if (Math.Abs(radius - radius2) < CurveAssistFunc.precision && center.DistanceTo(center2) < CurveAssistFunc.precision)
					{
						XYZ hyendPoint5 = arc.GetEndPoint(0);
						XYZ hyendPoint6 = arc.GetEndPoint(1);
						XYZ hyendPoint7 = arc2.GetEndPoint(0);
						XYZ hyendPoint8 = arc2.GetEndPoint(1);
						if (hyendPoint5.DistanceTo(hyendPoint7) < CurveAssistFunc.precision || hyendPoint5.DistanceTo(hyendPoint8) < CurveAssistFunc.precision || hyendPoint6.DistanceTo(hyendPoint7) < CurveAssistFunc.precision || hyendPoint6.DistanceTo(hyendPoint8) < CurveAssistFunc.precision)
						{
							XYZ startPnt = null;
							XYZ endPnt = null;
							XYZ radianPnt = null;
							if (hyendPoint5.DistanceTo(hyendPoint7) < CurveAssistFunc.precision)
							{
								startPnt = hyendPoint6;
								endPnt = hyendPoint8;
								radianPnt = hyendPoint5;
							}
							else if (hyendPoint5.DistanceTo(hyendPoint8) < CurveAssistFunc.precision)
							{
								startPnt = hyendPoint6;
								endPnt = hyendPoint7;
								radianPnt = hyendPoint5;
							}
							else if (hyendPoint6.DistanceTo(hyendPoint7) < CurveAssistFunc.precision)
							{
								startPnt = hyendPoint5;
								endPnt = hyendPoint8;
								radianPnt = hyendPoint6;
							}
							else if (hyendPoint6.DistanceTo(hyendPoint8) < CurveAssistFunc.precision)
							{
								startPnt = hyendPoint5;
								endPnt = hyendPoint7;
								radianPnt = hyendPoint6;
							}
							return uiApp.Application.CreatYJKArc(startPnt, endPnt, radianPnt);
						}
					}
				}
			}
			return null;
		}

		public static XYZ GetClosestPointTo(UIApplication uiApp, Curve curve, XYZ ptGive, bool extend)
		{
			double num = 30000.0;
			XYZ result = null;
			List<XYZ> list = new List<XYZ>();
			IntersectionResultArray intersectionResultArray = null;
			Line line = curve as Line;
			if (line != null)
			{
				XYZ xyz = line.GetEndPoint(0);
				XYZ xyz2 = line.GetEndPoint(1);
				XYZ xyz3 = (xyz2 - xyz).Normalize() * num / 2.0;
				XYZ xyz4 = RevitVersionFuncs.CreateRotationAtPoint(XYZ.BasisZ, Math.PI*.5, xyz).OfVector(xyz3);
				XYZ xyz5 = new XYZ(ptGive.X, ptGive.Y, xyz.Z);
				Line line2 = uiApp.Application.CreatYJKLine(xyz5 - xyz4, xyz5 + xyz4, true);
				if (extend)
				{
					xyz += xyz3;
					xyz2 = xyz - 2.0 * xyz3;
					Line line3 = uiApp.Application.CreatYJKLine(xyz, xyz2, true);
					line2.Intersect(line3, out intersectionResultArray);
				}
				else
				{
					line2.Intersect(line, out intersectionResultArray);
				}
			}
			Arc arc = curve as Arc;
			if (arc != null)
			{
				XYZ xyz6 = new XYZ(ptGive.X, ptGive.Y, arc.Center.Z) - arc.Center;
				Line line4 = uiApp.Application.CreatYJKLine(arc.Center - 2.0 * xyz6, arc.Center + 2.0 * xyz6, true);
				if (extend)
				{
					Arc arc2 = uiApp.ActiveUIDocument.Document.CreatYJKArc(arc.Center, arc.Radius, 0.0, Math.PI*2, XYZ.BasisX, XYZ.BasisY);
					line4.Intersect(arc2, out intersectionResultArray);
				}
				else
				{
					line4.Intersect(arc, out intersectionResultArray);
				}
			}
			if (intersectionResultArray != null)
			{
				for (int i = 0; i < intersectionResultArray.Size; i++)
				{
                    list.Add(intersectionResultArray.get_Item(i).XYZPoint);
				}
				double num2 = num;
				foreach (XYZ xyz7 in list)
				{
					double length = (ptGive - xyz7).GetLength();
					if (length < num2)
					{
						num2 = length;
						result = xyz7;
					}
				}
				return result;
			}
			return null;
		}

		public static XYZ GetCurveNormalVector(Curve curve, XYZ ptOnCurve)
		{
			XYZ xyz = XYZ.Zero;
			CurveType curveType = CurveAssistFunc.GetCurveType(curve);
			if (curveType == CurveType.eLine)
			{
				xyz = LineAssistFunc.GetVector(curve as Line).Normalize();
				xyz = CurveAssistFunc.Rotate(xyz, XYZ.BasisZ, Math.PI*.5);
			}
			else if (curveType == CurveType.eArc)
			{
				Arc arc = curve as Arc;
				xyz = (ptOnCurve - arc.Center).Normalize();
			}
			return xyz;
		}

		public static XYZ Rotate(XYZ vect, XYZ axis, double angle)
		{
			double x = axis.X;
			double y = axis.Y;
			double z = axis.Z;
			double[,] array = new double[3, 3];
			array[0, 0] = x * x;
			array[0, 1] = x * y;
			array[0, 2] = x * z;
			array[1, 0] = y * x;
			array[1, 1] = y * y;
			array[1, 2] = y * z;
			array[2, 0] = z * x;
			array[2, 1] = z * y;
			array[2, 2] = z * z;
			double[,] array2 = array;
			double[,] array3 = new double[3, 3];
			array3[0, 1] = -z;
			array3[0, 2] = y;
			array3[1, 0] = z;
			array3[1, 2] = -x;
			array3[2, 0] = -y;
			array3[2, 1] = x;
			double[,] array4 = array3;
			double[,] array5 = new double[3, 3];
			array5[0, 0] = 1.0 - array2[0, 0];
			array5[0, 1] = -array2[0, 1];
			array5[0, 2] = -array2[0, 2];
			array5[1, 0] = -array2[1, 0];
			array5[1, 1] = 1.0 - array2[1, 1];
			array5[1, 2] = -array2[1, 2];
			array5[2, 0] = -array2[2, 0];
			array5[2, 1] = -array2[2, 1];
			array5[2, 2] = 1.0 - array2[2, 2];
			double[,] array6 = array5;
			double[,] array7 = new double[3, 3];
			array7[0, 0] = array2[0, 0] + Math.Cos(angle) * array6[0, 0] + Math.Sin(angle) * array4[0, 0];
			array7[0, 1] = array2[0, 1] + Math.Cos(angle) * array6[0, 1] + Math.Sin(angle) * array4[0, 1];
			array7[0, 2] = array2[0, 2] + Math.Cos(angle) * array6[0, 2] + Math.Sin(angle) * array4[0, 2];
			array7[1, 0] = array2[1, 0] + Math.Cos(angle) * array6[1, 0] + Math.Sin(angle) * array4[1, 0];
			array7[1, 1] = array2[1, 1] + Math.Cos(angle) * array6[1, 1] + Math.Sin(angle) * array4[1, 1];
			array7[1, 2] = array2[1, 2] + Math.Cos(angle) * array6[1, 2] + Math.Sin(angle) * array4[1, 2];
			array7[2, 0] = array2[2, 0] + Math.Cos(angle) * array6[2, 0] + Math.Sin(angle) * array4[2, 0];
			array7[2, 1] = array2[2, 1] + Math.Cos(angle) * array6[2, 1] + Math.Sin(angle) * array4[2, 1];
			array7[2, 2] = array2[2, 2] + Math.Cos(angle) * array6[2, 2] + Math.Sin(angle) * array4[2, 2];
			double[,] array8 = array7;
			return new XYZ(array8[0, 0] * vect.X + array8[0, 1] * vect.Y + array8[0, 2] * vect.Z, array8[1, 0] * vect.X + array8[1, 1] * vect.Y + array8[1, 2] * vect.Z, array8[2, 0] * vect.X + array8[2, 1] * vect.Y + array8[2, 2] * vect.Z);
		}

		public static XYZ GetCurveTangentVector(Curve curve, XYZ ptOnCurve)
		{
			XYZ result = XYZ.Zero;
			CurveType curveType = CurveAssistFunc.GetCurveType(curve);
			if (curveType == CurveType.eLine)
			{
				result = LineAssistFunc.GetVector(curve as Line);
			}
			else if (curveType == CurveType.eArc)
			{
				result = ArcAssistFunc.GetArcTangentVector(curve as Arc, ptOnCurve);
			}
			return result;
		}

		public static OverlapType GetOverlapType(UIApplication uiApp, Curve c1, Curve c2)
		{
			OverlapType result = OverlapType.eNotOverlap;
			CurveType curveType = CurveAssistFunc.GetCurveType(c1);
			CurveType curveType2 = CurveAssistFunc.GetCurveType(c2);
			if (curveType == CurveType.eLine && curveType2 == CurveType.eLine)
			{
				Line line = c1 as Line;
				Line line2 = c2 as Line;
				result = LineAssistFunc.GetOverlapType(uiApp, line, line2);
			}
			else if (curveType == CurveType.eArc && curveType2 == CurveType.eArc)
			{
				Arc a = c1 as Arc;
				Arc a2 = c2 as Arc;
				result = ArcAssistFunc.GetOverlapType(uiApp, a, a2);
			}
			else if (c1 is Ellipse && c2 is Ellipse)
			{
				Ellipse e = c1 as Ellipse;
				Ellipse e2 = c2 as Ellipse;
				result = CurveAssistFunc.GetOverlapType(uiApp, e, e2);
			}
			return result;
		}

		public static bool IsPointOnCurve(UIApplication uiApp, XYZ pt, Curve curve)
		{
			return CurveAssistFunc.GetClosestPointTo(uiApp, curve, pt, false).IsAlmostEqualTo(pt);
		}

		public static bool IsParallel(Curve curve1, Curve curve2)
		{
			if (CurveAssistFunc.GetCurveType(curve1) != CurveAssistFunc.GetCurveType(curve2))
			{
				return false;
			}
			Line line = curve1 as Line;
			if (line != null)
			{
				Line line2 = curve2 as Line;
				return line.Direction.IsParallelTo(line2.Direction);
			}
			if (curve1 as Arc != null)
			{
				Arc arc = curve2 as Arc;
				return arc.Center.IsAlmostEqualTo(arc.Center);
			}
			return false;
		}

		public static OverlapType GetOverlapType(UIApplication uiApp, Ellipse e1, Ellipse e2)
		{
			XYZ zero = XYZ.Zero;
			XYZ zero2 = XYZ.Zero;
			if (!e1.Center.IsAlmostEqualTo(e2.Center))
			{
				return OverlapType.eNotOverlap;
			}
			double radiusX = e1.RadiusX;
			double radiusX2 = e2.RadiusX;
			if (radiusX != radiusX2)
			{
				return OverlapType.eNotOverlap;
			}
			double radiusX3 = e1.RadiusX;
			double radiusX4 = e2.RadiusX;
			if (radiusX3 != radiusX4)
			{
				return OverlapType.eNotOverlap;
			}
			return OverlapType.eOverlap;
		}

		protected static double precision = 1E-06;
	}
}
